﻿using System;
using System.Reflection;
using System.Windows.Input;
using MVVMFoundation;

namespace CredentialsManager.ViewModels
{
    /// <summary>
    /// Base class for all view models
    /// </summary>
    public class ViewModelBase : ObservableObject, IDisposable
    {
        #region Private member variables

        private bool m_IsLoading;
        private string m_ProgressMessage;
        private string m_DisplayName;
        private bool m_Disposed = false;
        private RelayCommand m_CloseCommand;

        #endregion

        #region Constructors/Destructor

        /// <summary>
        /// Constructs a new new model and registers with the Mediator
        /// </summary>
        public ViewModelBase()
        {
            // register all decorated methods to the Mediator
            m_IsLoading = false;
            Mediator.Instance.Register(this);
        }

        ~ViewModelBase()
        {
            OnDispose();
        }

        #endregion

        #region Public properties
        
        public bool IsLoading
        {
            get
            {
                return m_IsLoading;
            }
            protected set
            {
                m_IsLoading = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public string ProgressMessage
        {
            get
            {
                return m_ProgressMessage;
            }
            protected set
            {
                m_ProgressMessage = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        public string DisplayName
        {
            get
            {
                return m_DisplayName;
            }
            set
            {
                m_DisplayName = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        /// <summary>
        /// Mediator : Mediator = Messaging pattern
        /// </summary>
        public static Mediator Mediator
        {
            get { return Mediator.Instance; }
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Retrieves a service object identified by <typeparamref name="TServiceContract"/>.
        /// </summary>
        /// <typeparam name="TServiceContract">The type identifier of the service.</typeparam>
        public TServiceContract GetService<TServiceContract>()
            where TServiceContract : class
        {
            return ServiceContainer.Instance.GetService<TServiceContract>();
        }

        /// <summary>
        /// Invoked when this object is being removed from the application and will be subject to garbage collection.
        /// </summary>
        public void Dispose()
        {
            lock (this)
            {
                if (!m_Disposed)
                {
                    OnDispose();
                    m_Disposed = true;
                    GC.SuppressFinalize(this);
                }
            }
        }

        #endregion

        #region Public events

        /// <summary>
        /// Raised when this workspace should be removed from the UI.
        /// </summary>
        public event EventHandler RequestClose;

        #endregion

        #region Protected properties

        protected bool Disposed
        {
            get
            {
                lock (this)
                {
                    return m_Disposed;
                }
            }
        }

        #endregion

        #region Protected methods

        /// <summary>
        /// Child classes can override this to perform specific clean up.
        /// </summary>
        protected virtual void OnDispose()
        {
            // left for implementation in child classes
        }

        protected void OnRequestClose()
        {
            EventHandler handler = this.RequestClose;

            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        #endregion

        #region Commands

        public ICommand CloseCommand
        {
            get
            {
                return m_CloseCommand ?? (m_CloseCommand = new RelayCommand(
                    param => this.OnRequestClose()));
            }
        }

        #endregion        
    }
}